package com.xiaopangzi.study.spring.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 描述: AOP约定流程规范，绑定目标实体与拦截器
 *  InvocationHandler>>该接口只有一个方法，通过目标对象(proxy)、方法和参数就可以反射运行方法获取结果。
 * @author : sujinchen
 * @date : 2020/9/26
 */
public class ProxyBean implements InvocationHandler {
    /**
     * 拦截器
     */
    Interceptor interceptor;
    /**
     * 目标对象，被代理的对象
     */
    Object target;

    /**
     * 构造函数，绑定目标对象和拦截器
     * @param interceptor 拦截器
     * @param target 目标对象
     */
    public ProxyBean(Interceptor interceptor, Object target) {
        this.interceptor = interceptor;
        this.target = target;
    }

    /**
     * 获取代理对象，由JDK方式获取代理对象
     * @return 代理对象
     */
    public Object getProxyBean() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader()
                , target.getClass().getInterfaces(), this);
    }

    /**
     * 约定流程规则
     *
     * @param proxy  代理对象
     * @param method 对象方法
     * @param args   参数列表
     * @return 目标对象方法调用结果
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //通过目标对象生成调用器
        Invocation invocation = new Invocation(args, method, target);
        //保存调用目标对象方法返回结果
        Object result = null;
        boolean execeptionFlag = false;
        /**
         * 约定流程实现
         */
        this.interceptor.before();
        try {
            if (this.interceptor.useAround()) {
                this.interceptor.around(invocation);
            } else {
                result = invocation.proceed();
            }
        } catch (Exception e) {
            e.printStackTrace();
            execeptionFlag = true;
        }
        if (execeptionFlag) {
            this.interceptor.afterThrowing();
        } else {
            this.interceptor.afterReturn();
        }
        this.interceptor.after();
        return result;
    }


}
